package com.appkubes.fintech.restful.application.risk.data.xingpan.service.impl;

import com.appkubes.fintech.common.exption.BusinessException;
import com.appkubes.fintech.core.po.FintechRiskXingpangWithBLOBs;
import com.appkubes.fintech.core.po.FintechUser;
import com.appkubes.fintech.core.po.FintechUserBaseInfo;
import com.appkubes.fintech.restful.application.risk.data.xingpan.Constants;
import com.appkubes.fintech.restful.application.risk.data.xingpan.JsonUtil;
import com.appkubes.fintech.restful.application.risk.data.xingpan.SignUtil;
import com.appkubes.fintech.restful.application.risk.data.xingpan.dao.RiskXingpangDao;
import com.appkubes.fintech.restful.application.risk.data.xingpan.http.HttpService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * @Author: leeming
 * @Date: 2020-02-05 14:16
 * @Description:
 */
@Component
@Slf4j
public class AsyncCrawler {

    @Resource
    private RiskXingpangDao riskXingpangDao;

    @Value("${xingpang.data.appId}")
    private String appId;

    @Value("${xingpang.data.appSecret}")
    private String appSecret;

    @Async
    public void WaitingCrawler (String userKey,String crawlerId,String crawlerToken){
        HttpService httpService = HttpService.newInstance();
        while (true) {
            sleep(5000L); // 等待五秒后获取爬虫信息
            Map map = operateCrawler(httpService, Constants.CRAWLER_OPERATE_METHOD_CrawlerGetInfo, crawlerId, crawlerToken,null);
            if (!Constants.SUCCESS_CODE.equals(map.get("code"))) {
                log.error("获取爬虫信息失败：{}", map.get("message"));
                break;
            }
            Map dataMap = (Map) map.get("data");
            String status = (String) dataMap.get("status"); // Crawler运行状态
            if (Constants.CRAWLER_STATUS_Success.equals(status)) {
                log.info("数据爬取成功");
                // 可获取爬取结果
                String operatorReportData = operateCrawlerWithStr(httpService, Constants.CRAWLER_OPERATE_METHOD_CrawlerGetData, crawlerId, crawlerToken,null);
                String operatorData = operateCrawlerWithStr(httpService, Constants.CRAWLER_OPERATE_METHOD_CrawlerGetOriginalData, crawlerId, crawlerToken,null);
                log.info("数据爬取成功,运营商报告=" + operatorReportData);
                log.info("数据爬取成功,通话记录=" + operatorData);
                CacheCrawlerData(userKey,operatorData,operatorReportData);
            } else if (Constants.CRAWLER_STATUS_Crawling.equals(status)) {
                // do nothing
                // 等待五秒后再次尝试
                continue;
            } else {
                log.info("爬虫线程数据异常："+ dataMap);
            }
            break;
        }
    }

    public Map startCrawler(FintechUserBaseInfo baseInfo, String pass, String crawlerType) {
        HttpService httpService = HttpService.newInstance();
        Map map = createCrawler(httpService,crawlerType,baseInfo.getPhone(),pass,baseInfo.getRealName(),baseInfo.getIdentityNum());
        if (!Constants.SUCCESS_CODE.equals(map.get("code"))) {
            log.error("创建爬虫失败：{}", map.get("message"));
            throw new BusinessException("创建爬虫失败："+map.get("message"));
        }

        return map;
    }

    public Map createCrawler(HttpService httpService, String crawlerType, String username,String password,String identityName,String identityNo) {
        Map<String, String> params = new HashMap<>();
        params.put("appId", appId);
        params.put("crawlerType", crawlerType);
        params.put("username", username);
        params.put("password", password);
        params.put("identityName", identityName);
        params.put("identityNo", identityNo);
        params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));

        String sign = SignUtil.sign(params, appSecret);
        params.put("sign", sign);

        List<NameValuePair> nvps = new ArrayList<>();
        params.forEach((k, v) -> {
            nvps.add(new BasicNameValuePair(k, v));
        });

        HttpPost post = new HttpPost(Constants.CRAWLER_CREATE_URL);
        try {
            post.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

        String content = httpService.execAndReturnString(post);
        return JsonUtil.mapFromJson(content);
    }


    public Map operateCrawler(HttpService httpService, String method, String crawlerId, String crawlerToken, String appendData) {
        String content = operateCrawlerWithStr(httpService, method, crawlerId, crawlerToken, appendData);
        return JsonUtil.mapFromJson(content);
    }

    public String operateCrawlerWithStr(HttpService httpService, String method, String crawlerId, String crawlerToken, String appendData) {
        log.info("Try to operate crawler: method={}", method);

        Map<String, String> params = new HashMap<>();
        params.put("method", method);
        params.put("crawlerId", crawlerId);
        params.put("crawlerToken", crawlerToken);
        if (appendData != null) {
            params.put("appendData", appendData);
        }

        List<NameValuePair> nvps = new ArrayList<>();
        params.forEach((k, v) -> {
            nvps.add(new BasicNameValuePair(k, v));
        });

        HttpPost post = new HttpPost(Constants.CRAWLER_OPERATE_URL);
        try {
            post.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        String content;
        try{
            content = httpService.execAndReturnString(post);
        }catch (Throwable e){
            e.printStackTrace();
            log.info("begin retryOperateCrawlerWithStr crawlerId is {}",crawlerId);
            content = retryOperateCrawlerWithStr(post);
            log.info("end retryOperateCrawlerWithStr crawlerId is {}",crawlerId);
        }
        return content;
    }

    private String retryOperateCrawlerWithStr(HttpPost post){
        HttpService httpService = HttpService.newInstance();
        return httpService.execAndReturnString(post);
    }

    public int CacheCrawlerData(String userKey, String operatorData,String operatorReportData) {
        FintechRiskXingpangWithBLOBs rishXingpang = (FintechRiskXingpangWithBLOBs)riskXingpangDao.selectByPrimaryKey(userKey);
        rishXingpang.setUpdateTime(new Date());
        rishXingpang.setOperatorresult(operatorData);
        rishXingpang.setOperatorreportresult(operatorReportData);
        int result = riskXingpangDao.updateByPrimaryKeyWithBLOBs(rishXingpang);
        return result;
    }

    public static void sleep(Long millis) {
        try {
            Thread.sleep(millis); // 等待millis秒后继续
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
